package wind_service

/**
 * 使用Redis做MySQL缓存
 */

import (
	"strconv"
	"database/sql"
	"encoding/json"
	"github.com/garyburd/redigo/redis"
	_ "github.com/go-sql-driver/mysql"
	"github.com/name5566/leaf/log"
	"fmt"
)

var connection redis.Conn;
var database *sql.DB

func Connect() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		log.Error("connect to redis server [%s] failed:", ":6379", err)
		Disconnect()
		return
	}
	// defer c.Close()
	connection = c

	db, err := sql.Open("mysql", "root:123456@/user")
	if err != nil {
		log.Error("connect to mysql server [%s] failed: ", ":3306", err)
		Disconnect()
		return
	}
	err = db.Ping()
	if err != nil {
		log.Error("open connection of mysql failed. err: ", err)
		Disconnect()
		return
	}
	//defer db.Close()
	database = db
}
func Disconnect() {
	if connection != nil {
		connection.Close()
	}
	if database != nil {
		database.Close()
	}
}

const USERINFO_DBNAME string       = "userinfo"
const USERINFO_CACHE_PREFIX string = "user:info:"
const USERINFO_CACHE_EXPIRE int    = 3600

type UserInfo struct {
	UserId int64
	Username string
}

func getUserInfoKey(userId int64) string {
	key := USERINFO_CACHE_PREFIX + strconv.Itoa(userId)
	return key
}

// Get From Redis => Nope?? => Get From Mysql => Set Into Redis
func GetUserInfo(userId int64) (UserInfo, error) {
	key := getUserInfoKey(userId)

	// load data from redis
	value, err := connection.Do("get", key)
	if err != nil {
		log.Error("get data from redis failed. key %s err: ", key, err)
		return nil, err
	}

	userInfo := &UserInfo{}
	err = json.Unmarshal(value, userInfo)
	if err == nil {
		return userInfo, nil
	}

	log.Error("parse data from redis failed. key %s", key)

	userInfo, err = getUserInfo(userId)
	if err != nil {
		log.Error("get data from mysql failed. key %s err: ", key, err)
		return nil, err
	}

	go setUserInfo(userId, userInfo)
	return userInfo, nil
}

// Get From Mysql
func getUserInfo(userId int64) (UserInfo, error) {
	stmtOut, err := database.Prepare("SELECT UserId,Username FROM ? WHERE UserId = ?")
	if err != nil {
		log.Error("select sql prepared failed err: ", err)
		return nil, err
	}
	defer stmtOut.Close()

	var userInfo UserInfo
	err = stmtOut.QueryRow(USERINFO_DBNAME, userId).Scan(&userInfo)
	if err != nil {
		log.Error("select sql execute failed err: ", err)
		return nil, err
	}

	fmt.Printf("The UserInfo{ UserId: %d, Username: %s}", userInfo.UserId, userInfo.Username)

	return userInfo, nil
}

// Set Into Mysql => Set Into Redis
func SetUserInfo(userId int64, userInfo UserInfo) error {
	stmtIns, err := database.Prepare("INSERT INTO ? (UserId, Username) VALUES (?, ?) ON DUPLICATE KEY UPDATE UserId = ?, Username = ?")
	if err != nil {
		log.Error("update sql prepared failed err: ", err)
		return err
	}
	defer stmtIns.Close()

	_, err = stmtIns.Exec(USERINFO_DBNAME, userId, userInfo.Username, userId, userInfo.Username)
	if err != nil {
		log.Error("update sql execute failed. err: ", err)
		return err
	}

	go setUserInfo(userId, userInfo)
	return nil
}

// Set Into Redis
func setUserInfo(userId int64, userInfo UserInfo) error {
	key := getUserInfoKey(userId)

	value, err := json.Marshal(&userInfo)
	if err != nil {
		log.Error("parse data from mysql failed. key %s", key)
		return err
	}

	_, err = connection.Do("setex", key, USERINFO_CACHE_EXPIRE, value)
	if err != nil {
		log.Error("set mysql data info redis cache failed. key %s err: ", key, err)
		return err
	}
}
